package com.wangijun.yuan.web.service;


import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.wangijun.yuan.web.base.CommonPage;
import com.wangijun.yuan.web.base.CommonResult;
import com.wangijun.yuan.core.domain.Comment;
import com.wangijun.yuan.core.domain.OperateInfo;
import com.wangijun.yuan.core.model.em.OperateTypeEnum;
import com.wangijun.yuan.web.model.dto.CommentPageParam;
import com.wangijun.yuan.web.model.dto.CommentSaveParam;
import com.wangijun.yuan.web.model.dto.ReplyPageParam;
import com.wangijun.yuan.web.model.vo.PageInfo;
import com.wangijun.yuan.web.model.vo.ReplyCmtVO;
import com.wangijun.yuan.web.model.vo.UserInfoVO;
import com.wangijun.yuan.web.mapper.ArticleMapper;
import com.wangijun.yuan.web.mapper.CommentMapper;
import com.wangijun.yuan.core.util.IpUtil;
import com.wangijun.yuan.web.util.YuanWebUtil;
import com.wangijun.yuan.web.model.vo.CommentVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author readpage
 * @since 2023-02-03 16:15
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CommentService extends ServiceImpl<CommentMapper, Comment> {
    private final CommentMapper commentMapper;
    private final UserService userService;
    private final ArticleMapper articleMapper;
    private final OperateInfoService operateInfoService;

    private NoticeEventService getNoticeEventService() {
        return SpringUtil.getBean(NoticeEventService.class);
    }

    /**
     * 功能描述: 点赞或者取消点赞
     *
     * @author wlf 2024/6/28 16:44
     */
    public boolean liked(Long commentId) {
        return operateInfoService.operate(OperateTypeEnum.comment_like, commentId);
    }

    /**
     * 功能描述: 保存评论
     *
     * @author wlf 2024/3/16 0:21
     */
    public CommentVO add(CommentSaveParam commentSaveParam) {
        CommentVO comment = BeanUtil.copyProperties(commentSaveParam, CommentVO.class);
        comment.setId(IdWorker.getId());
        comment.setAddress("来自" + IpUtil.getAddr());
        comment.setLikes(0);
        comment.setUserId(StpUtil.getLoginIdAsLong());
        if (commentMapper.insert(comment) < 1) {
            throw new RuntimeException("评论发布错误");
        }
        comment.setRelativeTime(YuanWebUtil.dateRelative(comment.getCreateTime()));
        comment.setUserInfo(BeanUtil.copyProperties(userService.get(comment.getUserId()), UserInfoVO.class));
        comment.setReplyData(new PageInfo<>());
        // 评论数量加1
        articleMapper.commentAdd(comment.getArticleId(), 1);


        getNoticeEventService().artComment(comment);

        return comment;
    }

    /**
     * 功能描述: 分页获取文章下的评论
     *
     * @author wlf 2024/6/14 16:52
     */
    public CommonPage<CommentVO> list(CommentPageParam param, List<Long> commentIds) {
        LambdaQueryChainWrapper<Comment> wrapper = lambdaQuery()
                .eq(Comment::getArticleId, param.getArticleId())
                .eq(Comment::getParentId, 0);
        Page<Comment> page = wrapper.page(param.page());
        return CommonPage.toPage(page, CommentVO.class, comment -> {
            comment.setUserInfo(BeanUtil.copyProperties(userService.get(comment.getUserId()), UserInfoVO.class));
            Long id = comment.getId();
            // 合并redis中的点赞数量
            comment.setRelativeTime(YuanWebUtil.dateRelative(comment.getCreateTime()));
            comment.setLikedFlag(commentIds.contains(comment.getId()));
            // 分页查询回复
            ReplyPageParam pageParam = new ReplyPageParam();
            pageParam.setPageNum(1);
            pageParam.setPageSize(20);
            pageParam.setParentId(id);
            CommonPage<ReplyCmtVO> replyPage = reply(pageParam, commentIds);
            comment.setReplyCount(replyPage.getRecordCount());
            PageInfo<ReplyCmtVO> reply = new PageInfo<>();
            // 拷贝
            reply.setTotalPage(replyPage.getTotalPage());
            reply.setList(replyPage.getRows());
            reply.setTotal(replyPage.getRecordCount());
            reply.setPageNum(replyPage.getPageNum());
            reply.setPageSize(replyPage.getPageSize());

            comment.setReplyData(reply);
        });
    }

    /**
     * 功能描述: 分页获取评论下的回复评论
     *
     * @author wlf 2024/6/14 16:53
     */
    public CommonPage<ReplyCmtVO> reply(ReplyPageParam param, List<Long> commentIds) {
        // 通过parentId查询回复列表
        Page<Comment> replyList = this.lambdaQuery()
                .eq(Comment::getParentId, param.getParentId())
                .orderByAsc(Comment::getId)
                .page(param.page());
        return CommonPage.toPage(replyList, ReplyCmtVO.class, comment -> {
            if (!Objects.equals(comment.getParentId(), comment.getReplyId())) {
                Comment preCmt = this.getById(comment.getReplyId());
                if (preCmt == null) {
                    comment.setPreCmt(new ReplyCmtVO.PreCmt("", "原评论已删除"));
                } else {
                    comment.setPreCmt(new ReplyCmtVO.PreCmt(preCmt.getContent(),
                            userService.get(preCmt.getUserId()).getUsername()));
                }
            }
            comment.setRelativeTime(YuanWebUtil.dateRelative(comment.getCreateTime()));
            comment.setUserInfo(BeanUtil.copyProperties(userService.get(comment.getUserId()), UserInfoVO.class));
            // 合并redis中的点赞数量
            comment.setLikedFlag(commentIds.contains(comment.getId()));
        });
    }


    /**
     * 功能描述: 删除评论
     * 删除父评论，连带删除子评论
     *
     * @author wlf 2024/4/14 0:45
     */
    @Transactional
    public Integer del(Long commentId) {
        Comment comment = this.getById(commentId);
        if (comment != null) {
            if (comment.getUserId().equals(StpUtil.getLoginIdAsLong())) {
                // 评论数量减
                Long count = this.lambdaQuery().eq(Comment::getParentId, commentId).count();
                int resultNum = 1 + count.intValue();
                articleMapper.commentAdd(comment.getArticleId(), -1 * resultNum);
                // 删除评论
                removeById(commentId);
                // 删除评论子评论
                this.lambdaUpdate().eq(Comment::getParentId, commentId).remove();
                // 删除操作记录
                Db.lambdaUpdate(OperateInfo.class)
                        .eq(OperateInfo::getOperateType, OperateTypeEnum.article_like.getCode())
                        .eq(OperateInfo::getDataId, commentId).remove();
                return resultNum;
            } else {
                CommonResult.error("评论删除失败");
            }

        }
        return 0;
    }

}
